home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C++ / Frameworks / Sprocket Framework DR2 / Sprocket Framework / AEFutures.cp next >
Text File  |  1996-06-15  |  23KB  |  794 lines

  1. /*
  2.  
  3.     File:        AEFutures.cp
  4.     Project:    Sprocket Framework 1.1 (DR2), released 6/15/96
  5.     Contains:    Futures package
  6.     To Do:        ?
  7.  
  8.     Sprocket Major Contributors:
  9.     ----------------------------
  10.     Dave Falkenburg, producer of Sprocket 1.0
  11.     Bill Hayden,     producer of Sprocket 1.1
  12.     Steve Sisak,     producer of the upcoming Sprocket 2.0
  13.     
  14.     Pete Alexander        Steve Falkenburg    Randy Thelen
  15.     Eric Berdahl        Nitin Ganatra        Chris K. Thomas
  16.     Marshall Clow        Dave Hershey        Leonard Rosenthal
  17.     Tim Craycroft        Dave Mark            Dean Yu
  18.     David denBoer        Gary Powell
  19.     Cameron Esfahani    Jon Summers            Apple Computer, Inc.
  20.         
  21.     Comments, Additions, or Corrections:
  22.     ------------------------------------
  23.     Bill Hayden, Nikol Software <nikol@codewell.com>
  24.  
  25. */
  26.  
  27.  
  28. #include "AEFutures.h"
  29. #include "Semaphores.h"
  30. #include "SprocketMacros.h"
  31.  
  32. #ifndef __APPLEEVENTS__
  33. #include <AppleEvents.h>
  34. #endif
  35.  
  36. //
  37. // Keywords for special handlers not documented
  38. // in Inside Macintosh
  39. //
  40. #define keyAEBlock                    'blck'
  41. #define keyAEUnblock                'unbk'
  42.  
  43. //
  44. // Message ID of the event sent by AEResetTimer
  45. //
  46. #define kAEWaitLonger                'wait'
  47.  
  48. //
  49. // Random, arbitrarily choosen keyword 
  50. // for a parameter that probably doesn't exist.
  51. //
  52. #define keyNonexistantParameter        'nonx'
  53.  
  54. //
  55. // Structure used just to pass parameters to the "RedispatchEvent" thread
  56. //
  57. struct AsyncPredispatchParameters
  58. {
  59.     AppleEvent                        fAppleEvent;
  60.     AppleEvent                        fReply;
  61.     AEEventHandlerUPP                fEventHandler;
  62.     long                            fHandlerRefCon;
  63. };
  64.  
  65. typedef struct AsyncPredispatchParameters AsyncPredispatchParameters;
  66.  
  67. #if USESROUTINEDESCRIPTORS
  68.  
  69. //
  70. // The block and unblock special handlers are not
  71. // documented, so they do not have ProcInfo descriptions
  72. // for their callback in the Universal headers.  Both
  73. // the block and the unblock routine take a single parameter:
  74. // the AppleEvent that is being blocked on / unblocked.
  75. //
  76. enum
  77. {
  78.     uppAEBlockUnblockProcInfo = kPascalStackBased
  79.          | RESULT_SIZE(SIZE_CODE(sizeof(OSErr)))
  80.          | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(AEDesc*)))
  81. };
  82.  
  83. #endif
  84.  
  85. //
  86. // Private constants:
  87. //
  88. #define kCreateSemaphoreIfNotFound            true
  89. #define kDontCreateSemaphoreIfNotFound        false
  90.  
  91.  
  92. //
  93. // Private functions:
  94. //
  95. static OSErr NewFuturesThread(ThreadEntryProcPtr threadEntry, void *threadParam, long handlerRefCon, ThreadID *threadMade);
  96. static TSemaphore* GetFutureSemaphore(AppleEvent* reply, Boolean createIfNotFound);
  97. static pascal OSErr AEBlock(AppleEvent* reply);
  98. static pascal OSErr AEUnblock(AppleEvent* reply);
  99. static pascal OSErr WaitLongerEvent(AppleEvent* ae, AppleEvent* reply, long refCon);
  100. static pascal OSErr AsyncPreDispatchHandler(AppleEvent* ae, AppleEvent* reply, long refCon);
  101. static void RedispatchEvent(void* threadParam);
  102. static OSErr GetAEMHandlerUPPFromOneTable(AEEventClass theAEEventClass, AEEventID theAEEventID, AEEventHandlerUPP *handler, long *handlerRefcon, Boolean isSysHandler);
  103. static OSErr GetAppleEventHandlerUPP(AppleEvent* ae, AEEventHandlerUPP *handler, long *handlerRefCon);
  104. static long PrivateFuturesThread(long threadParam);
  105. static void FillInDefaultTimeoutValues(long& timeout);
  106.  
  107.  
  108. #if USESROUTINEDESCRIPTORS
  109.  
  110. static RoutineDescriptor gAEBlockRD                        = BUILD_ROUTINE_DESCRIPTOR(uppAEBlockUnblockProcInfo, AEBlock);
  111. static RoutineDescriptor gAEUnblockRD                    = BUILD_ROUTINE_DESCRIPTOR(uppAEBlockUnblockProcInfo, AEUnblock);
  112. static RoutineDescriptor gWaitLongerEventRD                = BUILD_ROUTINE_DESCRIPTOR(uppAEEventHandlerProcInfo, WaitLongerEvent);
  113. static RoutineDescriptor gAsyncPreDispatchRD            = BUILD_ROUTINE_DESCRIPTOR(uppAEEventHandlerProcInfo, AsyncPreDispatchHandler);
  114.  
  115. #endif // USESROUTINEDESCRIPTORS
  116.  
  117. //
  118. // Globals:
  119. //
  120. ThreadCreateProcPtr gThreadCreateProc                    = nil;
  121.  
  122.  
  123.  
  124. /*****************************************************************************/
  125.  
  126.  
  127.  
  128. // Install the block and unblock routines.
  129. //
  130. // If spawnHousekeepingThread is true, then a thread will be forked to idle the
  131. // Futures package.  If you pass false for this boolean, your code must call
  132. // IdleFutures Periodicly.
  133. //
  134. // If installAsyncPreDispatchHandler is true, then the futures package will
  135. // install a predispatch handler that automatically forks a new thread every
  136. // time AEProcessAppleEvents is called, so that all of your application's
  137. // event handlers may be processed asynchronously.
  138.  
  139.  
  140. OSErr InitFutures(ThreadCreateProcPtr threadCreateProc, long initFuturesFlags)
  141. {
  142.     ThreadID futuresHousekeepingThreadID = kNoThreadID;
  143.     OSErr err = noErr;
  144.  
  145.     TSemaphore::InitializeGlobals();
  146.     
  147.     gThreadCreateProc = threadCreateProc;
  148.     
  149. #if USESROUTINEDESCRIPTORS
  150.     if(err == noErr)
  151.         err = AEInstallSpecialHandler(keyAEBlock, &gAEBlockRD, false);
  152.     if(err == noErr)
  153.         err = AEInstallSpecialHandler(keyAEUnblock, &gAEUnblockRD, false);
  154.     if(err == noErr)
  155.         err = AEInstallEventHandler(kCoreEventClass, kAEWaitLonger, &gWaitLongerEventRD, 0, false);
  156. #else
  157.     if(err == noErr)
  158.         err = AEInstallSpecialHandler(keyAEBlock, (UniversalProcPtr) AEBlock, false);
  159.     if(err == noErr)
  160.         err = AEInstallSpecialHandler(keyAEUnblock, (UniversalProcPtr) AEUnblock, false);
  161.     if(err == noErr)
  162.         err = AEInstallEventHandler(kCoreEventClass, kAEWaitLonger, (AEEventHandlerProcPtr) &WaitLongerEvent, 0, false);
  163. #endif
  164.     
  165.     //
  166.     // Create the housekeeping thread.
  167.     // We could probably use a very small stack for this thread.
  168.     //
  169.     if((err == noErr) && (initFuturesFlags & kSpawnHousekeepingThread))
  170.         err = NewFuturesThread((ThreadEntryProcPtr)PrivateFuturesThread, 0, 0, &futuresHousekeepingThreadID);
  171.     
  172.     //
  173.     // If an async pre-dispatch handler was requested, then install it.
  174.     //
  175.     if((err == noErr) && (initFuturesFlags & kInstallAsyncPreDispatchHandler))
  176.     {
  177. #if USESROUTINEDESCRIPTORS
  178.         err = AEInstallSpecialHandler(keyPreDispatch, &gAsyncPreDispatchRD, false);
  179. #else
  180.         err = AEInstallSpecialHandler(keyPreDispatch, (UniversalProcPtr)AsyncPreDispatchHandler, false);
  181. #endif        
  182.     }
  183.     
  184.     return err;
  185. }
  186.  
  187.  
  188.  
  189. /*****************************************************************************/
  190.  
  191.  
  192.  
  193. // Block the current thread until the specified message becomes real.  This function
  194. // works by accessing a nonexistant parameter of the reply; the AppleEvent manager will
  195. // block any access to the reply, since (obviously) it doesn't know what the parameters
  196. // of the reply will be until the reply actually arrives.
  197.  
  198.  
  199. void BlockUntilReal(AppleEvent* reply)
  200. {
  201.     long            nonExistentParameterStorage;
  202.     long            actualSize;
  203.     DescType        typeCode;
  204.  
  205.  
  206.     // Ask for the non existent parameter; this will cause the AppleEvent manager
  207.     // to block on the event
  208.  
  209.     AEGetParamPtr(reply, keyNonexistantParameter, typeLongInteger, &typeCode, (Ptr) &nonExistentParameterStorage, sizeof(long), &actualSize);
  210. }
  211.  
  212.  
  213.  
  214. /*****************************************************************************/
  215.  
  216.  
  217.  
  218. // Return 'true' if the reply can be accessed without blocking, or false if it
  219. // is still a future
  220.  
  221.  
  222. Boolean ReplyArrived(AppleEvent* ae)
  223. {
  224.     UniversalProcPtr    oldBlockRoutine = nil;
  225.     long                nonExistentParameterStorage;
  226.     long                actualSize;
  227.     DescType            typeCode;
  228.     Boolean                arrived = false;
  229.  
  230.     OSErr err = AEGetSpecialHandler(keyAEBlock, &oldBlockRoutine, false);
  231.     if(err == noErr)
  232.         err = AERemoveSpecialHandler(keyAEBlock, oldBlockRoutine, false);
  233.  
  234.     //
  235.     // Ask for the non existent parameter; this will cause the AppleEvent
  236.     // manager to return errAEReplyNotArrived if the reply is still a future;
  237.     // some other error (such as paramter not found) will be returned if
  238.     // the reply has arrived
  239.     //
  240.     if(err == noErr)
  241.     {
  242.         arrived = (AEGetParamPtr(ae, keyNonexistantParameter, typeLongInteger, &typeCode, (Ptr) &nonExistentParameterStorage, sizeof(long), &actualSize) != errAEReplyNotArrived);
  243.         err = AEInstallSpecialHandler(keyAEBlock, oldBlockRoutine, false);
  244.     }
  245.  
  246.     return arrived;
  247. }
  248.  
  249.  
  250.  
  251. /*****************************************************************************/
  252.  
  253.  
  254.  
  255. // Specify how long the reply should wait in between reset-timer notifications, and
  256. // how much total time the reply should wait before giving up on a server that keeps
  257. // reseting the timer but never delivers results.
  258.  
  259.  
  260. void SetReplyTimeoutValue(AppleEvent* reply, long timeoutValue /* = kNeverTimeoutSemaphore */, long maxWaitTime /* = kNeverTimeoutSemaphore */)
  261. {
  262.     FillInDefaultTimeoutValues(timeoutValue);
  263.     FillInDefaultTimeoutValues(maxWaitTime);
  264.     
  265.     TSemaphore* semaphore = GetFutureSemaphore(reply, kCreateSemaphoreIfNotFound);
  266.     if(semaphore)
  267.         {
  268.         // DebugStr("\pSet reply timout value");
  269.         semaphore->SetSemaphoreTimoutValue(timeoutValue);
  270.         semaphore->SetSemaphoreMaxWaitTime(maxWaitTime);        
  271.         }
  272.     else
  273.         DebugMessage("\pCouldn't make semaphore to set timeout value");
  274. }
  275.  
  276.  
  277.  
  278. /*****************************************************************************/
  279.  
  280.  
  281.  
  282. // Usually, this routine doesn't need to be called, as it is done automatically by
  283. // the private futures thread, installed by InitFutures.
  284.  
  285.  
  286. void IdleFutures()
  287. {
  288.     TSemaphore::Idle();
  289. }
  290.  
  291.  
  292.  
  293. /*****************************************************************************/
  294.  
  295.  
  296.  
  297. OSErr AskForFuture(AppleEvent* ae, AppleEvent* reply, long timeoutValue /* = kAEDefaultTimeout */, long maxWaitTime /* = 0x7FFFFFFF */, AESendMode sendMode, AESendPriority sendPriority /* = kAENormalPriority */)
  298. {
  299.     OSErr err = noErr;
  300.     
  301.     FillInDefaultTimeoutValues(timeoutValue);
  302.     
  303.     long resetFrequency = timeoutValue / 2;
  304.     
  305.     err = AEPutAttributePtr(ae, keyAEResetTimerFrequencyAttr, typeLongInteger, (Ptr)&resetFrequency, sizeof(long));
  306.     if(err == noErr)
  307.         err = AESend(ae, reply, sendMode | kAEWaitReply, sendPriority, 0, nil, nil);
  308.     if(err == errAETimeout)
  309.         err = noErr;
  310.     if(err == noErr)
  311.         SetReplyTimeoutValue(reply, timeoutValue, maxWaitTime);
  312.  
  313.     return err;
  314. }
  315.  
  316.  
  317.  
  318. /*****************************************************************************/
  319.  
  320.  
  321.  
  322. // Determines how frequently a server application is advised to call AEResetTimer
  323.  
  324.  
  325. long GetResetTimerFrequency(AppleEvent* ae)
  326. {
  327.     DescType typeCode;
  328.     long actualSize;
  329.     long resetTimerFrequency = 0;
  330.     
  331.     //
  332.     // First look at keyAEResetTimerFrequencyAttr; if that attribute
  333.     // does not exist, try half of keyAETimeoutAttr
  334.     //
  335.     if(AEGetAttributePtr(ae, keyAEResetTimerFrequencyAttr, typeLongInteger, &typeCode, (Ptr)&resetTimerFrequency, sizeof(long), &actualSize) != noErr)
  336.     {
  337.         if(AEGetAttributePtr(ae, keyTimeoutAttr, typeLongInteger, &typeCode, (Ptr)&resetTimerFrequency, sizeof(long), &actualSize) == noErr)
  338.             resetTimerFrequency /= 2;
  339.         else
  340.             resetTimerFrequency = 0;
  341.     }
  342.     
  343.     //
  344.     // If we couldn't find a frequency, use the default
  345.     //
  346.     if(resetTimerFrequency == 0)
  347.         resetTimerFrequency = kDefaultResetTimerFrequency;
  348.     
  349.     return resetTimerFrequency;
  350. }
  351.  
  352.  
  353.  
  354. /*****************************************************************************/
  355.  
  356.  
  357.  
  358. // Calls AEResetTimer if enough time has elapsed.
  359.  
  360.  
  361. OSErr ResetTimerIfNecessary(AppleEvent* reply, unsigned long* lastReset, long resetFrequency)
  362. {
  363.     OSErr err = noErr;
  364.     unsigned long currentTime = TickCount();
  365.     
  366.  
  367.     // Set up 'lastReset' the first time in
  368.  
  369.     if(*lastReset == 0)
  370.         *lastReset = currentTime;
  371.     
  372.     // We won't be so extreme as to enforce a minimum reset
  373.     // frequency, but we don't allow zero!
  374.  
  375.     if(resetFrequency == 0)
  376.         resetFrequency = kDefaultResetTimerFrequency;
  377.     
  378.     // TimeExpired is in Semaphores.c; it determines if 'currentTime' has
  379.     // gone beyond 'lastReset + resetFrequency', handling the unavoidable
  380.     // tickcount wraparound that happens every 771 days.
  381.  
  382.     if (TimeExpired(currentTime, *lastReset, *lastReset + resetFrequency))
  383.         {
  384.         // DebugStr("\pAbout to call AEResetTimer");
  385.         
  386.         *lastReset = currentTime;
  387.         err = AEResetTimer(reply);
  388.         }
  389.     
  390.     return err;
  391. }
  392.  
  393.  
  394.  
  395. /*****************************************************************************/
  396.  
  397.  
  398.  
  399. // This routine calls either 'NewThread' or the application-defined thread creation
  400. // procedure.
  401.  
  402.  
  403. static OSErr NewFuturesThread(ThreadEntryProcPtr threadEntry, void *threadParam, long handlerRefCon, ThreadID *threadMade)
  404. {
  405.     OSErr err = noErr;
  406.     Size stackSize = 0;
  407.     ThreadOptions options = kCreateIfNeeded | kFPUNotNeeded;
  408.     
  409.     if(gThreadCreateProc != nil)
  410.         err = (*gThreadCreateProc)(threadEntry, threadParam, handlerRefCon, threadMade);
  411.     else
  412.         err = NewThread(kCooperativeThread, threadEntry, threadParam, stackSize, options, nil, threadMade);
  413.     
  414.     return err;
  415. }
  416.  
  417.  
  418.  
  419. /*****************************************************************************/
  420.  
  421.  
  422.  
  423. // This function returns the semaphore that this event is blocked on, or
  424. // nil if the event is not blocked
  425.  
  426.  
  427. static TSemaphore* GetFutureSemaphore(AppleEvent* reply, Boolean createIfNotFound)
  428. {
  429.     TSemaphore* semaphore = nil;
  430.     long semaphoreID = 0;
  431.  
  432.  
  433.     // Use the reply's return ID as the semaphore ID.
  434.     //
  435.     // We need to set the semaphore ID when the current thread
  436.     // blocks on the future; once the reply arrives, we need to
  437.     // pull the semaphore ID out of the reply.  Therefore, we'd
  438.     // better use an attribute that exists before and after the
  439.     // reply arrives.
  440.     //
  441.     // Another important point:  we can access the return ID attribute
  442.     // without causing the block routine to be called--very important,
  443.     // as we need to get the semaphore out of the message from
  444.     // within the block routine!
  445.  
  446.     DescType typeCode;
  447.     long actualSize;
  448.     
  449.     if(AEGetAttributePtr(reply, keyReturnIDAttr, typeLongInteger, &typeCode, (Ptr)&semaphoreID, sizeof(long), &actualSize) == noErr)
  450.         semaphore = TSemaphore::FindSemaphore(semaphoreID, createIfNotFound, 0);
  451.     else
  452.         DebugMessage("\pCould not get return attr from reply");
  453.     
  454.     return semaphore;
  455. }
  456.  
  457.  
  458.  
  459. /*****************************************************************************/
  460.  
  461.  
  462.  
  463. // This routine is installed as the special handler "block", which is called by the
  464. // AppleEvent manager whenever a routine that tries to extract information from a
  465. // future (an AppleEvent reply that has not yet arrived) is called.
  466.  
  467.  
  468. static pascal OSErr AEBlock(AppleEvent* reply)
  469. {
  470.     TSemaphore*            semaphore = nil;
  471.     OSErr                err = noErr;
  472.  
  473.     
  474.     // DebugStr("\pAEBlock");
  475.     
  476.     // Look up the semaphore attached to this message.  This will
  477.     // only rarely exist; the only time that it would exist would
  478.     // be if multiple threads tried to pull information out of
  479.     // the same future.  In that case, the first thread would create
  480.     // the semaphore, and the second thread would then get and
  481.     // block on the same semaphore.
  482.     //
  483.     semaphore = GetFutureSemaphore(reply, kCreateSemaphoreIfNotFound);
  484.         
  485.     // If we have a semaphore, then block on it.
  486.     // 'errAETimeout' is one error that may come out of 'Grab' (if we go to sleep
  487.     // for a while, then give up).  Note, however, that the AppleEvent manager will always
  488.     // return errAEReplyNotArrived if AEBlock returns anything other than noErr.
  489.  
  490.     if(semaphore != nil)
  491.         {
  492.         err = semaphore->Grab();
  493.         semaphore->Release();
  494.         }
  495.  
  496.     // If we can't block, then return
  497.     // errAEReplyNotArrived right away
  498.  
  499.     else
  500.         err = errAEReplyNotArrived;
  501.             
  502.     return err;
  503. }
  504.  
  505.  
  506.  
  507. /*****************************************************************************/
  508.  
  509.  
  510.  
  511. // This function is called by the AppleEvent manager when a future that was blocked
  512. // on becomes a real event (i.e., when the reply actually arrives).  When that happens,
  513. // we need to unblock all threads that are blocked on this future.
  514.  
  515.  
  516. static pascal OSErr AEUnblock(AppleEvent* reply)
  517. {
  518.     TSemaphore*            semaphore = nil;
  519.     OSErr                err = noErr;
  520.  
  521.  
  522.     // DebugStr("\pAEUnblock");
  523.     
  524.     // The AppleEvent manager may call the unblock routine
  525.     // even if the block routine was never called, so there
  526.     // may or may not be a semaphore attached to the message
  527.     //
  528.     semaphore = GetFutureSemaphore(reply, kDontCreateSemaphoreIfNotFound);
  529.     if (semaphore != nil)
  530.         {
  531.         // DebugStr("\pAbout to release all threads");
  532.         semaphore->Dispose();
  533.         }
  534.     
  535.     return err;
  536. }
  537.  
  538.  
  539.  
  540. /*****************************************************************************/
  541.  
  542.  
  543.  
  544. // Notify the reply that some activity was reported from the server. 
  545.  
  546.  
  547. static pascal OSErr WaitLongerEvent(AppleEvent* ae, AppleEvent* /*reply*/, long /*refCon*/)
  548. {
  549.     // DebugStr("\pWaitLongerEvent");
  550.     
  551.     // Note that the return ID of the wait longer event
  552.     // is the same as the return ID of the reply whose
  553.     // semaphore we want to look up; the reply to the
  554.     // wait longer event is not used for anything, because
  555.     // the AppleEvent manager sends the wait longer event
  556.     // "no reply".
  557.  
  558.     TSemaphore* semaphore = GetFutureSemaphore(ae, kDontCreateSemaphoreIfNotFound);
  559.     if(semaphore)
  560.         {
  561.         // DebugStr("\pFound semaphore to reset timer on");
  562.         semaphore->ResetTimeoutTimer();
  563.         }
  564.     else
  565.         DebugMessage("\pGot wait longer event but did not find semaphore");
  566.     
  567.     return noErr;
  568. }
  569.  
  570.  
  571.  
  572. /*****************************************************************************/
  573.  
  574.  
  575.  
  576. static pascal OSErr AsyncPreDispatchHandler(AppleEvent* ae, AppleEvent* reply, long /*refCon*/)
  577. {
  578.     // By default, assume that we are not going to handle this event;
  579.     // If we return 'errAEEventNotHandled', the AppleEvent manager will
  580.     // continue dispatching this event.  We let the AEM handle events
  581.     // without any handler, and events that would be handled by a system
  582.     // event handler (which we know will never yield, and therefore
  583.     // do not need to run in a thread).
  584.  
  585.     OSErr err = errAEEventNotHandled;
  586.     AsyncPredispatchParameters** dispatchParams = nil;
  587.     AEEventHandlerUPP handler = nil;
  588.     long handlerRefCon = 0;
  589.     
  590.     // Look up the event handler and refCon in the AppleEvent tables;
  591.     // if we can't find a handler, then we'll let the AppleEvent
  592.     // manager do the dispatching.
  593.  
  594.     if(GetAppleEventHandlerUPP(ae, &handler, &handlerRefCon) == noErr)
  595.         {
  596.         dispatchParams = (AsyncPredispatchParameters**)NewHandle(sizeof(AsyncPredispatchParameters));
  597.         if(dispatchParams != nil)
  598.             {
  599.             // Save the AppleEvent message and reply.  We don't need to
  600.             // save the event handler's refCon, because the AppleEvent
  601.             // manager will look it up again when the event is redispatched.
  602.  
  603.             (*dispatchParams)->fAppleEvent        = *ae;
  604.             (*dispatchParams)->fReply            = *reply;
  605.             (*dispatchParams)->fEventHandler    = handler;
  606.             (*dispatchParams)->fHandlerRefCon    = handlerRefCon;
  607.                 
  608.             // Make a new thread
  609.  
  610.             ThreadID newThreadID;
  611.             if(NewFuturesThread((ThreadEntryProcPtr)RedispatchEvent, (void*)dispatchParams, handlerRefCon, &newThreadID) == noErr)
  612.                 {
  613.                 dispatchParams = nil;
  614.  
  615.                 // Always suspend the current event.  AEResumeTheCurrentEvent
  616.                 // will be called to redispatch the event after it has been
  617.                 // forked into a thread.
  618.  
  619.                 AESuspendTheCurrentEvent(ae);
  620.             
  621.                 // Set 'err' to 'noErr', indicating that we have handled the event.
  622.  
  623.                 err = noErr;
  624.                 }
  625.             }
  626.         }
  627.  
  628.     // If the 'dispatchParams' were created, but we couldn't
  629.     // fork a new thread, then dispose of them here.  Otherwise,
  630.     // they will be disposed when the event is redispatched.
  631.  
  632.     if(dispatchParams != nil)
  633.         DisposeHandle((Handle)dispatchParams);
  634.     
  635.     return err;
  636. }
  637.  
  638.  
  639.  
  640. /*****************************************************************************/
  641.  
  642.  
  643.  
  644. static void RedispatchEvent(void* threadParam)
  645. {
  646.     OSErr err = noErr;
  647.     
  648.     // Extract the AppleEvent, Reply, event handler UPP and
  649.     // message refCon from the thread parameter, which we
  650.     // know is a handle to our predispatch parameters. 
  651.  
  652.     AsyncPredispatchParameters** dispatchParams = (AsyncPredispatchParameters**)threadParam;
  653.     AppleEvent ae = (*dispatchParams)->fAppleEvent;
  654.     AppleEvent reply = (*dispatchParams)->fReply;
  655.     AEEventHandlerUPP handler = (*dispatchParams)->fEventHandler;
  656.     long handlerRefCon = (*dispatchParams)->fHandlerRefCon;
  657.     DisposeHandle((Handle)dispatchParams);
  658.     
  659.     // Call the event handler directly
  660.  
  661.     err = CallAEEventHandlerProc(handler, &ae, &reply, handlerRefCon);
  662.     
  663.     // If the event handler returned an error, we need to do
  664.     // exactly what the AppleEvent manager would do in the
  665.     // same situation:  jam the error into keyErrorNumber
  666.     // iff there isn't a keyErrorNumber in the reply already.
  667.     // This is necessary because there is no way to pass
  668.     // the error code into AEResumeTheCurrentEvent
  669.  
  670.     if(err != noErr)
  671.         {
  672.         DescType actualType = typeNull;
  673.         long actualSize = 0;
  674.         long errorResult = 0;
  675.         
  676.         if(AEGetParamPtr(&reply, keyErrorNumber, typeLongInteger, &actualType, &errorResult, sizeof(long), &actualSize) != noErr)
  677.             {
  678.             errorResult = err;
  679.             AEPutParamPtr(&reply, keyErrorNumber, typeLongInteger, &errorResult, sizeof(long));
  680.             }
  681.         }
  682.     
  683.     // When our handler returns, call AEResumeTheCurrentEvent
  684.     // without dispatching, so that the AppleEvent manager
  685.     // will send the reply.
  686.  
  687.     AEResumeTheCurrentEvent(&ae, &reply, (AEEventHandlerUPP)kAENoDispatch, 0);
  688. }
  689.  
  690.  
  691.  
  692. /*****************************************************************************/
  693.  
  694.  
  695.  
  696. static OSErr GetAEMHandlerUPPFromOneTable(AEEventClass theAEEventClass, AEEventID theAEEventID, AEEventHandlerUPP *handler, long *handlerRefCon, Boolean isSysHandler)
  697. {
  698.     OSErr err = AEGetEventHandler(theAEEventClass, theAEEventID, handler, handlerRefCon, isSysHandler);
  699.     if(err != noErr)
  700.         err = AEGetEventHandler(typeWildCard, theAEEventID, handler, handlerRefCon, isSysHandler);
  701.     if(err != noErr)
  702.         err = AEGetEventHandler(theAEEventClass, typeWildCard, handler, handlerRefCon, isSysHandler);
  703.     if(err != noErr)
  704.         err = AEGetEventHandler(typeWildCard, typeWildCard, handler, handlerRefCon, isSysHandler);
  705.         
  706.     return err;
  707. }
  708.  
  709.  
  710.  
  711. /*****************************************************************************/
  712.  
  713.  
  714.  
  715. static OSErr GetAppleEventHandlerUPP(AppleEvent* ae, AEEventHandlerUPP *handler, long *handlerRefCon)
  716. {
  717.     AEEventClass theAEEventClass;
  718.     AEEventID theAEEventID;
  719.     DescType actualType = typeNull;
  720.     long actualSize = 0;
  721.     
  722.  
  723.     // Look up the event class and the event ID of the AppleEvent
  724.     // so that we can look it up in the event handler dispatch table
  725.  
  726.     OSErr err = AEGetAttributePtr(ae, keyEventClassAttr, typeType, &actualType, &theAEEventClass, sizeof(AEEventClass), &actualSize);
  727.     if(err == noErr)
  728.         err = AEGetAttributePtr(ae, keyEventIDAttr, typeType, &actualType, &theAEEventID, sizeof(AEEventID), &actualSize);
  729.  
  730.     if(err == noErr)
  731.     {
  732.         err = GetAEMHandlerUPPFromOneTable(theAEEventClass, theAEEventID, handler, handlerRefCon, false);
  733.  
  734. #if 0
  735.     //
  736.     // We don't need to search the system event handler table, because we can
  737.     // let AEResumeTheCurrentEvent(kAEUseStandardDispatch) do that.  We know
  738.     // that system event handlers don't yield, so this is safe.
  739.     //
  740.         if(err != noErr)
  741.             err = GetAEMHandlerUPPFromOneTable(theAEEventClass, theAEEventID, handler, handlerRefCon, true);
  742. #endif
  743.     }
  744.     
  745.     return err;
  746. }
  747.  
  748.  
  749.  
  750. /*****************************************************************************/
  751.  
  752.  
  753.  
  754. // This thread does periodic tasks for the Futures package; currently, it only checks
  755. // to see if there are any futures that have timed out.  Note that TSemaphore::Idle
  756. // calls TickCount(), and performs no action most of the time.
  757. //
  758. // Unfortunately, there's no way for this thread to tell the thread manager that it
  759. // doesn't need to be swapped in for a number of ticks; it has to keep getting scheduled,
  760. // do nothing, get scheduled again, and so on for most of its life.
  761.  
  762.  
  763. static long PrivateFuturesThread(long /* threadParam */)
  764. {
  765.     for(;;)
  766.     {
  767.         IdleFutures();
  768.         YieldToAnyThread();
  769.     }
  770.     
  771.     return 0;
  772. }
  773.  
  774.  
  775.  
  776. /*****************************************************************************/
  777.  
  778.  
  779.  
  780. // This function converts from negative default constants to the actual positive
  781. // number that the constant is translated into.
  782.  
  783.  
  784. static void FillInDefaultTimeoutValues(long& timeout)
  785. {
  786.     //
  787.     // ••• What should the default timeout be?
  788.     //
  789.     if(timeout == kAEDefaultTimeout)
  790.         timeout = 1200;
  791.     else if(timeout < 0)
  792.         timeout = 0x7FFFFFFF;
  793. }
  794.